#include <ArduinoJson.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <ESP8266WiFi.h>
#include <ArduinoOTA.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <String.h>
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ D5, /* data=*/ D6, /* reset=*/ U8X8_PIN_NONE);
HTTPClient http;
struct Time_c {
  char time[6];
} Time_c = {
  "08:30"
};
struct Day
{
  int cod;
  char date[11];
  char range[10];
  char status[20];
};
struct Weather
{
  Day tody;
  Day tom;
  Day afterTom;
  char now[4];
  char pm25[10];
  char city[20];
  char qlty[10];
  char date[24];
  char time[6];
  char title[20];
  char detail1[20];
  char detail2[20];
  char detail3[20];
  char detail4[20];
  // char detail5[16];
} weather = {
  {0,
   "2017-01-17",
   "-- | --C",
   "Loading..."},
  {0,
   "2017-01-18",
   "-- | --C",
   "Loading..."},
  {0,
   "2017-01-19",
   "-- | --C",
   "Loading..."},
  "--",
  "PM25: ---",
  "CityName",
  "Loading",
  "2017-01-17 Tuesday",
  "08:30",
  "推送",
  "本地默认消息",
  "测试",
  "中文测试",
  "中文测试"};
//   // ""};
bool WIFIReady = false;
String WEBFWVers;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTPUrl, 3600*8, 60000);

void startProcess(char *title, int num)
{  
  u8g2.setCursor(14, 30);
  u8g2.print(title);
  u8g2.drawRFrame(9, 17, 110, 30, 5);
  u8g2.drawFrame(14, 36, 100, 6);
  u8g2.drawBox(14, 36, num, 6);
}


void statusUI(char *title, int num, bool isFirst)
{
  u8g2.setFont(u8g2_font_wqy12_t_gb2312);
  isFirst = isFirst;
  u8g2.clearBuffer();
  startProcess(title, num);
  u8g2.sendBuffer();
}

String getMAC()
{
  uint8_t mac[6];
  char result[14];
  snprintf(result, sizeof( result ), "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  return String(result);
}

void jsonParse(String j, bool isFirst)
{
  statusUI("数据解析中...", 20, isFirst);
  DynamicJsonDocument doc(2048);
  statusUI("数据解析中...", 25, isFirst);
  deserializeJson(doc, j);
  yield();
  Serial.print("Parse JSON: ");
  Serial.println(j);
  Serial.print("Parseing.....");
  yield();
  statusUI("数据解析中...", 30, isFirst);
  JsonObject root = doc.as<JsonObject>();
  yield();
  weather.tody.cod = root["value"]["tody"]["status"];
  strcpy(weather.tody.date, root["value"]["tody"]["date"]);
  strcpy(weather.tody.range, root["value"]["tody"]["range"]);
  strcpy(weather.tody.status, root["value"]["tody"]["s"]);
  statusUI("数据解析中...", 40, isFirst);
  yield();
  weather.tom.cod = root["value"]["tom"]["status"];
  strcpy(weather.tom.date, root["value"]["tom"]["date"]);
  strcpy(weather.tom.range, root["value"]["tom"]["range"]);
  strcpy(weather.tom.status, root["value"]["tom"]["s"]);
  statusUI("数据解析中...", 50, isFirst);
  yield();
  weather.afterTom.cod = root["value"]["afterTom"]["status"];
  strcpy(weather.afterTom.date, root["value"]["afterTom"]["date"]);
  strcpy(weather.afterTom.range, root["value"]["afterTom"]["range"]);
  strcpy(weather.afterTom.status, root["value"]["afterTom"]["s"]);
  statusUI("数据解析中...", 60, isFirst);
  yield();
  strcpy(weather.now, root["value"]["tody"]["now"]);
  strcpy(weather.pm25, root["value"]["pm25"]);
  strcpy(weather.city, root["value"]["city"]);
  strcpy(weather.qlty, root["value"]["qlty"]);
  statusUI("数据解析中...", 70, isFirst);
  yield();
  strcpy(weather.title, root["value"]["title"]);
  strcpy(weather.detail1, root["value"]["detail"][0]);
  strcpy(weather.detail2, root["value"]["detail"][1]);
  strcpy(weather.detail3, root["value"]["detail"][2]);
  strcpy(weather.detail4, root["value"]["detail"][3]);
  strcpy(weather.detail4, root["value"]["detail"][4]);
  statusUI("数据解析中...", 80, isFirst);
  yield();
  Serial.println("[Succes]");
  statusUI("JsonParse Successful!", 100, isFirst);
}

void XWWeatherGet(char *url, bool isFirst)
{
  statusUI("Start Http Get!", 0, isFirst);
  yield();
  Serial.print("Starting HTTP Request to: ");
  Serial.println(url);
  yield();
  http.begin(url);
  yield();
  statusUI("开始网络请求", 10, isFirst);
  int temp = http.GET();
//  if (http.GET() == 200)
//  {
  Serial.println("Succes");
  yield();
  statusUI("网络请求成功", 20, isFirst);
  String j = http.getString();
  http.end();
  yield();
  jsonParse(j, isFirst);
//  }
//  else
//  {
//  statusUI("网络请求失败，请重启", 20, isFirst);
//  Serial.println("Get Fail......  code:");
//  Serial.println(http.GET());
//  String j = http.getString();
//  http.end();
//  }
}

void NTPRequest(bool isFirst)
{
  Serial.print("SYNC Time with NTP Server '");
  Serial.print(NTPUrl);
  Serial.println("'...");
  timeClient.update();
  yield();
  String j = timeClient.getFormattedTime();
  const char* z = j.c_str();
  Serial.println("Succes:");
  Serial.println("********");
  Serial.println(z);
  Serial.println("********");
  yield();
  char times[6];
  times[0] = z[0];
  times[1] = z[1];
  times[2] = z[2];
  times[3] = z[3];
  times[4] = z[4];
  strcpy(Time_c.time, times);
}

void u8g2Begin()
{
  u8g2.begin();
  u8g2.enableUTF8Print();
  u8g2.setFlipMode(0);
  u8g2.setColorIndex(1);
}

void XWWifiBegin(char *url)
{
  statusUI("WiFi 连接中...", 0, true);
  Serial.println("Begin WIFI Connect.....");
  statusUI("WiFi 连接中...", 35, true);
  WiFi.mode(WIFI_STA);
  Serial.print("Use the last successful configuration");
  WiFi.begin();
  for (int i = 0; i < 50; i++)
  {
  int wstatus = WiFi.status();
  if (wstatus == WL_CONNECTED)
  {
    Serial.println("[Success]");
    Serial.printf("SSID: %s\r\n", WiFi.SSID().c_str());
    Serial.printf("PSW: %s\r\n", WiFi.psk().c_str());
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    statusUI("WiFi 连接成功！", 100, true);
    NTPRequest(true);
    WIFIReady = true;
    break;
  }
  else
  {
    Serial.print(".");
    statusUI("WiFi 连接中...", i+35, true);
    delay(200);
  }
  }
  if (!WIFIReady)
  {
  Serial.println("E:Not found configuration/AP Not found!" );
  statusUI("连接失败!", 0, true);
  delay(1000);
  Serial.print("Start SmartConfig");
  statusUI("Airkiss配网中...", 50, true);
  WiFi.beginSmartConfig();
  while (1)
  {
    Serial.print(".");
    if (WiFi.smartConfigDone())
    {
    Serial.println("[Success]");
    Serial.printf("SSID: %s\r\n", WiFi.SSID().c_str());
    Serial.printf("PSW: %s\r\n", WiFi.psk().c_str());
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    WiFi.setAutoConnect(true);  // 设置自动连接
    NTPRequest(true);
    WIFIReady = true;
    break;
    }
    delay(200); // 这个地方一定要加延时，否则极易崩溃重启 喂狗
  }
  }
  timeClient.begin();
}

void XWOTA(const char *FWUrlBase, const String FW_VERSION)
{
  WiFiClient client;
  ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
  Serial.println("Checking for firmware update...");
  statusUI("固件更新检查...", 20, true);
  delay(100);
  String VerE = ".ver.txt";
  String FWUrl = FWUrlBase;
  String FWUrlVer = FWUrl+VerE;
  Serial.print("firmware URL is '");
  Serial.print(FWUrl);
  Serial.print("'And Version file URL is '");
  Serial.print(FWUrlVer);
  Serial.println("'");
  http.begin(FWUrlVer);
  delay(10);
  int httpCode = http.GET();
  statusUI("固件更新检查...", 30, true);
  if( httpCode == 200 ) {
  WEBFWVers = http.getString();
  statusUI("固件更新检查...", 40, true);
  Serial.print("WEB firmware version is ");
  Serial.println(WEBFWVers);
  delay(5);
  Serial.print("Current firmware version: ");
  Serial.println(FW_VERSION);
  Serial.print("Available firmware version: ");
  Serial.println(WEBFWVers);
  statusUI("固件更新检查...", 60, true);
  }
  http.end();
  statusUI("固件更新检查...", 100, true);
  delay(1000);
  if(WEBFWVers != FW_VERSION) {
  Serial.print("Online Update firmware...");
  statusUI("正在进行固件更新", 50, true);
  ESPhttpUpdate.rebootOnUpdate(false);
  t_httpUpdate_return ret = ESPhttpUpdate.update(client, FWUrl);
  switch (ret) {
    case HTTP_UPDATE_FAILED:
    Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s , Loading Current firmware.\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
    statusUI("固件更新失败!", 0, true);
    delay(200);
    break;
    case HTTP_UPDATE_OK:
    Serial.println("[Succus]");
    statusUI("固件更新成功!", 100, true);
    delay(1000);
    ESP.restart();
    break;
  }
  }
  delay(500);
}

void OnlineFlash()
{
  Serial.print("Wait 5 Secound and check Flash.....");
  pinMode(0, INPUT);
  int beginm = millis();
  bool flashFLAG = false;
  while(millis()-beginm<=5000)
  {
  if(!digitalRead(0))
  {
    flashFLAG = true;
    break;
  }
  yield();
  }
  Serial.println("[Succes]");
  if(flashFLAG)
  {
    Serial.println("Local Firmware Update Hooking...");
    XWWifiBegin(url);
    statusUI("监听本地固件更新", 50, true);
    ArduinoOTA.onStart([]() {
      String type;
      String label;
      if (ArduinoOTA.getCommand() == U_FLASH) {
        type = "firmware";
      } else { // U_SPIFFS
        type = "filesystem";
      }
      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Begin update " + type + "...");
      if (ArduinoOTA.getCommand() == U_FLASH) {
        type = "固件";
      } else { // U_SPIFFS
        type = "文件";
      }
      label = "正在更新";
      label.concat(type);
      label.concat(" %0");
      statusUI(const_cast<char*>(label.c_str()), 0, true);
    });
    ArduinoOTA.onEnd([]() {
      Serial.println("\nSuccus");
      statusUI("固件更新成功!", 100, true);
      delay(1000);
    });
    ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\n", (progress / (total / 100)));
      String type;
      String label;
      if (ArduinoOTA.getCommand() == U_FLASH) {
        type = "固件";
      } else { // U_SPIFFS
        type = "文件";
      }
      label = "正在更新";
      label.concat(type);
      label.concat(" %");
      label.concat((progress / (total / 100)));
      statusUI(const_cast<char*>(label.c_str()), (progress / (total / 100)), true);
      yield();
    });
    ArduinoOTA.onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      statusUI("固件更新失败!", 0, true);
      if (error == OTA_AUTH_ERROR) {
        Serial.println("Auth Failed");
      } else if (error == OTA_BEGIN_ERROR) {
        Serial.println("Begin Failed");
      } else if (error == OTA_CONNECT_ERROR) {
        Serial.println("Connect Failed");
      } else if (error == OTA_RECEIVE_ERROR) {
        Serial.println("Receive Failed");
      } else if (error == OTA_END_ERROR) {
        Serial.println("End Failed");
      }
      delay(1000);
    });
    ArduinoOTA.begin();
    ArduinoOTA.setHostname("XWeather Station Firmware Update Client");
    
    while(true)
    {
      ArduinoOTA.handle();
      yield();
    }
  }
}

void XWBootFunc(char *url, const char *FWUrlBase, const String FW_VERSION)
{
  Serial.begin(115200);
  Serial.println("");
  Serial.println("--------Debug Info--------");
  Serial.print("IOT Weather Station ");
  Serial.print(FW_VERSION);
  Serial.println(" By xrh0905");
  Serial.print("MAC Address is ");
  Serial.println(getMAC());
  Serial.println("Initzation...");
  Serial.print("Light up PWR LED.....");
  pinMode(D0, OUTPUT);
  digitalWrite(D0, LOW);
  Serial.println("[Succes]");
  Serial.print("Begin u8g2 library.....");
  u8g2Begin();
  Serial.println("[Success]");
  Serial.print("Draw ICON.....");
  u8g2.clearBuffer();
  u8g2.drawXBMP(0,0,128,64,logo);
  u8g2.sendBuffer();
  Serial.println("[Succes]");
  OnlineFlash();
  u8g2.clearBuffer();
  u8g2.sendBuffer();
  XWWifiBegin(url);
  XWOTA(FWUrlBase, FW_VERSION);
  XWWeatherGet(url, true);
  Serial.println("Initzation Succes.");
}
